﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace CubeCalculations
{
   public class EvoCubex
   {
      private Cubex BaseCube;
      private static Cubex EvoCube;
      public EvoCubex(Cubex Cube)
      {
         BaseCube = new Cubex();
         BaseCube.ResetCube();
         Cube.CopyTo(BaseCube);
         EvoCube = new Cubex();
         EvoCube.ResetCube();
      }
      bool CheckSolution(int ExpectedSteps)
      {
         int s = BaseCube.SolveCube();
         if (s != 0)
            return false;
         return BaseCube.Solution().Count == ExpectedSteps;
      }

      public List<int> EvaluateSolutions(out int SolutionImprovement)
      {
         int s = BaseCube.SolveCube();
         if (s != 0)
         {
            SolutionImprovement = 0;
            return new List<int>();
         }
         int SolutionLen = BaseCube.Solution().Count;

         int CurrentSolutionLen, BestSolutionLen, OverAllBestSolution, BaseSteps = 0;
         int[] CurrentSolution, BestSoltuion;
         List<int[]> CompleteSolution = new List<int[]>();

         Random random = new Random((int)DateTime.Now.Ticks);
         var gSol = random.Next(20, 40);

         OverAllBestSolution = SolutionLen;
         int NoBetterSolutionFound = 0;

         //gesamte anzahl an Lösungsabzweigungen durchlaufen
         for (int x = 0; x < gSol; x++)
         {

            //Beste, aktuelle Lösung zurücksetzen
            BestSolutionLen = int.MaxValue;
            BestSoltuion = null;

            //10 Schritte generieren und den besten raussuchen
            for (int i = 0; i < 10; i++)
            {
               //Basiswürfel kopieren, und die bereits berechneten schritte Ausführen
               BaseCube.CopyTo(EvoCube);
               BaseSteps = EvaluateSolution(CompleteSolution, EvoCube);

               //Neue Lösung Generieren, und Lösungslänge zu den aktuellen Schritten addieren
               CurrentSolution = GenerateSolutions(1, 5);
               //CurrentSolutionLen += BaseSteps;

               ///Test
               {
                  List<int[]> cList = new List<int[]>(CompleteSolution);
                  cList.Add(CurrentSolution);
                  BaseCube.CopyTo(EvoCube);
                  BaseSteps = EvaluateSolution(cList, EvoCube);
                  EvoCube.SolveCube();
                  CurrentSolutionLen = EvoCube.Solution().Count + BaseSteps;

               }

               //Neue lösung übernehmen, wenn diese Besser ist
               if (CurrentSolutionLen < BestSolutionLen)
               {
                  BestSolutionLen = CurrentSolutionLen;
                  BestSoltuion = CurrentSolution;
               }
            }

            //Wenn die generierte Lösung besser ist, diese übernehmen
            if (BestSolutionLen < OverAllBestSolution)
            {
               //Schritte hinzufügen, Lösungslänge aktualisieren
               CompleteSolution.Add(BestSoltuion);
               OverAllBestSolution = BestSolutionLen;
               NoBetterSolutionFound = 0;
            }
            else
            {
               if (++NoBetterSolutionFound > 50)
                  break;

            }
         }

         BaseCube.CopyTo(EvoCube);
         EvaluateSolution(CompleteSolution, EvoCube);
         EvoCube.SolveCube();
         BestSolutionLen = EvoCube.Solution().Count;

         var result = new List<int>();
         foreach (var ints in CompleteSolution)
         {
            BestSolutionLen += ints.Length;
            result.AddRange(ints);
         }
         SolutionImprovement = OverAllBestSolution - SolutionLen;
         return result;
      }
      int EvaluateSolution(List<int[]> Moves ,Cubex Cube)
      {
         int Steps = 0;
         foreach (var move in Moves)
         {
            for (int i = 0; i < move.Length; i++)
            {
               Cube.CubeRotation[i]();
               Steps++;
            }
         }
         return Steps;
      }
      //private delegate void CubeRotations();
      //static CubeRotations[] cubeRotations;
      //static string[] sRotations;
      //private static CubeRotations[] cubeMoves;


      //int GenerateMoveSolutions(int Index)
      //{
      //      cubeMoves[Index]();
      //   EvoCube.SolveCube();
      //   return EvoCube.Solution().Count;
      //}
      int[] GenerateSolutions(int MinRotations, int MaxRotations)
      {
         //Random neu initialisieren
         Random r = new Random((int)DateTime.Now.Ticks);

         //Zufallszahl mithlfe der Parameter erstellen
         int rotations = r.Next(MinRotations, MaxRotations);

         //Solution-Array Initialisiern
         var Solution = new int[rotations];

         //Lösungen generieren und ausführen
         for (int i = 0; i < rotations; i++)
         {
            Solution[i] = r.Next(0, EvoCube.CubeRotation.Length);
            EvoCube.CubeRotation[Solution[i]]();
         }

         ////Würfel lösen
         //EvoCube.SolveCube();
         //RLen = EvoCube.Solution().Count + rotations;
         return Solution;
      }
   }
}
